2_plasma.f90 Source File


Source Code

module plasma
    !! модуль параметров плазмы
    use kind_module  
    implicit none
    integer ngrid, nspl
    !! ASTRA radial grid number
    real(wp) tcur
    !! время (придумать название для переменной получше)
    real(wp) rm
    !! minor radius in mid-plane, cm
    real(wp) b_tor0
    !! тороидальное магнитное поле
    !! временно нужно две переменных, тоже нужно исправить
    real(wp) b_tor
    !! тороидальное магнитное поле

    real(wp) r0
    real(wp) z0
    real(wp) rh1
    real(wp), dimension(:),allocatable:: con,tem,temi,zeff,afld
    real(wp), dimension(:),allocatable:: rh,rha,drhodr,delta,ell,gamm,amy

    real(wp) tet1, tet2
    !!common /a0a2/ 

    real(wp) xmi,cnye,cnyi,xsz,vt0 
    !!/a0ef3/ xmi,cnye,cnyi,xsz,vt0 
    real(wp) cnstvc

    real(wp) ww
    !!common /a0ef2/ ww

    real(wp) cltn
    !!common /a0ef1/ cltn    

    real(wp) vperp(50,100),cnstal,zza,zze,valfa!,kv
    !common /a0i5/ vperp(50,100),cnstal,zza,zze,valfa!,kv

    real(wp) vpmax

    real(wp) vk(100), sk(100)
    !common /a0i2/ vk(100)

    integer, parameter :: ipsy = 5, ncoef = 5
    !!   ipsy = number of polinomial decomposition coefficients
    !!   used for interpolation of Zakharov's moments.
    real(wp), dimension(ipsy) :: cdl,cly,cgm,cmy,coeffs


    real(wp) y2dn(501),y2tm(501),y2tmi(501)
    !!common /a0l3/
    real(wp) y2zeff(501)
    !!common /a0l5/ 

    integer ncheb
    real(wp) chebne(50),chebdne(50),chebddne(50)    
    !!common/ne_cheb

    real(wp) enorm(100), fst(100)
    !! em поле и еще что-то
contains
    subroutine init_plasma(NA1, ABC, BTOR, RTOR, UPDWN, GP2, AMETR, RHO, SHIF, ELON, TRIA,MU, NE, TE, TI, ZEF, UPL)
        use constants
        use approximation
        use rt_parameters
        use spline_module
        use chebyshev
        use math_module
        implicit none
        integer, intent(in)  :: NA1
        real(wp), intent(in) :: ABC, BTOR, RTOR, UPDWN, GP2
        real(wp), dimension(*) :: AMETR, RHO, SHIF, ELON, TRIA,MU,  NE, TE, TI, ZEF, UPL
        integer i, k
        integer, parameter :: N  = 501
        real(wp) :: znak_tor, znak_pol, fpol, dfmy

        ngrid = NA1
        nspl = ngrid
        if (.not. allocated(rh)) then
            allocate(rh(N),rha(N),drhodr(N),con(N),tem(N), source=0.0_wp)
            allocate(temi(N),zeff(N), afld(N), source=0.0_wp)
            allocate(delta(N),ell(N),gamm(N),amy(N), source=0.0_wp)
        end if
        do i=1, ngrid
            rh(i)=AMETR(i)/ABC
            rha(i)=RHO(i)/ABC  !/ABC instead of /ROC is not a mistake!
            delta(i)=(SHIF(1)-SHIF(i))/ABC  !FRTC Shafr. shift. defin.
            ell(i)=ELON(i)
            gamm(i)=rh(i)*TRIA(i)
            con(i)=NE(i)
            tem(i)=TE(i)
            temi(i)=TI(i)
            zeff(i)=ZEF(i)
            afld(i)=UPL(i)/RTOR/GP2 !!variant
        end do
        rh(ngrid)=1.d0
        rh1=rh(1)          !saving the first ASTRA radial grid element
        rh(1) = 0.0d0         !shifting the first element to zero
        rha(1) = 0.0d0        !shifting the first element to zero
        delta(1) = 0.0d0      !putting delta(rh=0.)=0.
        gamm(1) = 0.0d0       !putting gamm(rh=0.)=0.
   
        b_tor0=1.d4*BTOR*RTOR/(RTOR+SHIF(1)) !B_tor_(magnetic axis), Gauss
        rm=1.d2*ABC                       !minor radius in mid-plane, cm
        r0=1.d2*(RTOR+SHIF(1))     !x-coordinate of the magnetic axis, cm
        z0=1.d2*UPDWN              !z-coordinate of the magnetic axis, cm


    !   spline approximation of plasma profiles         
    !
    !   shift as a function of "minor radius":
        call approx(rh,delta,ngrid,polin1,ipsy-1,coeffs)
        cdl(1)=0.0d0
        do k=2,ipsy
            cdl(k)=coeffs(k-1)
        end do
 
    !   triangularity as a function of "minor radius":
        call approx(rh,gamm,ngrid,polin1,ipsy-1,coeffs)
        cgm(1)=0.0d0
        do k=2,ipsy
            cgm(k)=coeffs(k-1)
        end do
 
    !   ellipticity as a function of "minor radius":
        call approx(rh,ell,ngrid,polin,ipsy,cly)            

    !  "poloidal magnetic field":
        call diff(rh,rha,ngrid,drhodr)
 
        do i=2,ngrid
            amy(i)=1.d4*BTOR*MU(i)*rha(i)*drhodr(i)
            !print *, amy(i), BTOR, MU(i)
        end do
        !print *, '----------------'
        amy(1)=0.d0  
        
    !! amy=(btor/q)*rho*(drho/dr) is a function of "minor radius" r=rh(i).
    !! Poloidal magnetic field: B_pol=amy(r)*sqrt(g22/g), where g is
    !! determinant of 3D metric tensor and g22 is the (22) element of
    !! the tensor, normalized on ABC^4 and ABC^2, correspondingly.
    !!
    !!  Polinomial approximation of the amy(r):
    !    inpt2=ngrid-3
        call approx(rh,amy,ngrid-3,polin1,ipsy-1,coeffs)
        cmy(1)=0.d0
        do k=2,ipsy
         cmy(k)=coeffs(k-1)
        end do
  
        ! зачем-то меняет знак коэффициентов????
        znak_tor=dsign(1.d0,dble(itor))
        b_tor=znak_tor*dabs(b_tor0)
        fpol=fdf(1.d0,cmy,ncoef,dfmy)
        znak_pol=dsign(1.d0,dble(i_pol))*dsign(1.d0,fpol)
        do i=1,ncoef
         cmy(i)=znak_pol*cmy(i)
        end do

        
    !!!!!!!!!!!!!!! spline approximation of plasma profiles !!!!!!!!!!!!!!!!
        call splne(rh,con,nspl,y2dn)
        call splne(rh,tem,nspl,y2tm)
        call splne(rh,zeff,nspl,y2zeff)
        call splne(rh,temi,nspl,y2tmi)

        if(inew.ne.0) then
            ncheb=20
            call chebft1(zero,1.d0,chebne,ncheb,fn)
            call chder(zero,1.d0,chebne,chebdne,ncheb)
            call chder(zero,1.d0,chebdne,chebddne,ncheb)
        end if    
        
        call init_parameters
        call find_volums_and_surfaces

    end subroutine

    subroutine init_parameters
        use constants
        use approximation
        use rt_parameters
        implicit none
        real(wp) :: xly, xlyp, arg1, arg2  
        real(wp) :: hr, dn1, dn2, dn3, sss
    !!!   
        xly = fdf(one,cly,ncoef,xlyp)
        arg1=(zplus-z0)/(xly*rm)
        arg2=(zminus-z0)/(xly*rm)
        if(dabs(arg1).lt.1.d0) then
            tet1=dasin(arg1)      ! upper grill corner poloidal coordinate
        else
            tet1=0.5d0*pi         ! upper grill corner poloidal coordinate
        end if
        if(dabs(arg2).lt.1.d0) then
            tet2=dasin(arg2)      ! lower grill corner poloidal coordinate
        else
            tet2=-0.5d0*pi        ! lower grill corner poloidal coordinate
        end if   
        
        !------------------------------------------------------------
        ! calculate constants
        !---------------------------------------
        hr = 1.d0/dble(nr+1)        
        dn1=1d0/(zi1+dni2*zi2+dni3*zi3)
        dn2=dni2*dn1
        dn3=dni3*dn1
        sss=zi1**2*dn1/xmi1+zi2**2*dn2/xmi2+zi3**2*dn3/xmi3
        xmi=1836.d0/sss
        cnstvc=(.75d0*piq*sss/1836.d0)**one_third
        ww=freq*pi2*1.0d+09
        cnye=xlog/pi4
        cnyi=dsqrt(2d0)/(3d0*piq) !%for Vt=sqrt(Te/m)
        vt0=fvt(zero)
        !!!!!!!!      ptkev=ft(zero)/0.16d-8  !Te in keV
        cltn=clt/vt0
        xsz=clt/ww/rm
        !ccur=pqe*vt0*0.333d-9
        !!      ccurnr=pqe*pqe*0.333d-9/pme
        rrange=rrange*hr !ToDo если вызывается несколько раз то будут проблемы
        
        valfa=1.d9*dsqrt(1.91582d0*talfa/xmalfa)
        !  valfa (cgs units) = birth velocity
        zza=cnst1*(zalfa/xmalfa/valfa)**2*(clt/valfa)**3/pi
        zze=cnst2*2.d9*freq
        cnstal=(dsqrt(cnst1)/xmalfa/pi)*(zalfa*vt0/valfa)**2*clt/valfa
        vpmax=dsqrt(energy/talfa)
        !  "vpmax" in valfa velocity units !        
    end subroutine

    subroutine write_plasma(time_stamp)
        real(wp), intent(in) :: time_stamp
        character(120) fname
        integer, parameter :: iu = 20
        integer i
        write(fname,'("lhcd/plasma/", f9.7,".dat")')  time_stamp
        print *, fname
        open(iu, file=fname, status = 'new')
        write (iu, '(A)'), '#vars'
        write (iu, '(14A23)') 'b_tor0', 'rm', 'r0', 'z0'
        write (iu, ' (14(ES23.14))') b_tor0, rm, r0, z0
        write (iu, *) 

        write (iu, '(A)'), '#approx'
        write (iu, '(14A23)') 'cdl', 'cly', 'cgm', 'cmy'
        do i=1, ncoef
            write (iu, ' (14(ES23.14))') cdl(i),cly(i),cgm(i),cmy(i)
        end do  
        write (iu, *) 

        write (iu, '(A)'), '#radial_data'
        write (iu, '(14A23)') 'rh', 'rha', 'delta', 'ell', 'gamm', 'con', 'tem', 'temi', 'zeff', 'afld' 
        do i=1, ngrid
            write (iu, ' (14(ES23.14))') rh(i), rha(i), delta(i), ell(i), gamm(i), con(i), tem(i), temi(i), zeff(i), afld(i)
        end do                    

        close(iu)

    end subroutine

    subroutine write_lcms
        !! write lcms
        use constants
        use approximation
        integer, parameter :: iu = 20
        integer  :: i
        real(wp) :: xr, th
        real(wp) :: xdl, xdlp, xly, xlyp, xgm, xgmp
        real(wp) :: x, xx, z, zz, pl, pc, pa
        real(wp) :: cotet, sitet
        open(iu,file='lhcd/out/lcms.dat')
        write(iu,*)'     R(m)            Z(m)'
        write(iu,*)
        xr=1.d0
        xdl=fdf(xr,cdl,ncoef,xdlp)
        xly=fdf(xr,cly,ncoef,xlyp)
        xgm=fdf(xr,cgm,ncoef,xgmp)
        do i=1,101
            th=dble(i-1)*pi2/dble(100)
            cotet=dcos(th)
            sitet=dsin(th)
            xx=-xdl+xr*cotet-xgm*sitet**2
            zz=xr*xly*sitet
            x=(r0+rm*xx)/1d2
            z=(z0+rm*zz)/1d2
            write(iu,'(6(e13.6,3x))') x,z
        end do
        close(iu)
    end subroutine

    subroutine find_volums_and_surfaces
        use constants
        use rt_parameters, only: nr
        implicit none
        integer j
        real(wp) hr, rxx, vk0, sk0
        real(wp), parameter :: eps=1.d-6
        !--------------------------------------------------------
        ! find volums and surfaces
        !--------------------------------------------------------
        hr = 1.d0/dble(nr+1)
        vk0=pi2*hr*rm**3
        sk0=hr*rm**2
        do j=1,nr
            rxx=hr*dble(j)
            vk(j)=vk0*gaussint(obeom, zero, pi2, rxx, eps)
            sk(j)=sk0*gaussint(ploshad, zero, pi2, rxx, eps)
        end do        
    end subroutine

    real(wp) function fn(x)
    !! plasma  density,  cm^-3
        use constants, only: zero
        use spline_module      
        real(wp), intent(in) :: x
        real(wp) :: pa, r, y, dy
        real(wp), parameter :: alfa=4.d0, dr=.02d0
        pa=dabs(x)
        if(pa.le.rh(nspl)) then
            call splnt(rh,con,y2dn,nspl,pa,y,dy)
        else
            r=pa-rh(nspl)
            y=con(nspl)*dexp(-alfa*(r/dr)**2)
        end if
        fn=y*1.d+13    !cm^-3
    end    

    real(wp) function fvt(r)
    !! нет описания
        real(wp), intent(in) :: r
        real(wp) :: pt
        pt=ft(r)
        fvt=sqrt(pt/9.11d-28)
    end

    real(wp) function fn1(x,fnp)
    !! plasma density and its derivative
        use constants, only: zero
        use spline_module      
        real(wp), intent(in) :: x
        real(wp), intent(out) :: fnp
        real(wp) :: r, pa, y1, y, s, dy, dy1 
        real(wp), parameter :: alfa=4.d0, dr=.02d0
        pa=abs(x)
        if(pa.le.rh(nspl)) then
            call splnt(rh,con,y2dn,nspl,pa,y,dy)
        else
            call splnt(rh,con,y2dn,nspl,rh(nspl),y1,dy1)
            r=pa-rh(nspl)
            y=rh(nspl)*exp(-alfa*(r/dr)**2)
            dy=-2.d0*alfa*y*r/dr**2 !corrected
        end if
        fn1=y*1.d+13    !cm^-3
        fnp=dy*1.d+13
    end

    real(wp) function fn2(r, fnp, fnpp)
    !! plasma density and its first and second derivatives
        use constants, only: zero
        use chebyshev
        real(wp), intent(in) :: r
        real(wp), intent(out) :: fnp, fnpp
        real(wp) :: x, y1, y, s, dy, ddy 
        real(wp), parameter :: alfa=4.d0, dr=.02d0
        x=abs(r)
        if(x.le.1.d0) then
            y=chebev(zero,1.d0,chebne,ncheb,x)
            dy=chebev(zero,1.d0,chebdne,ncheb,x)
            ddy=chebev(zero,1.d0,chebddne,ncheb,x)
        else
            y1=chebev(zero,1.d0,chebne,ncheb,1.d0)
            s=x-1.d0
            y=y1*exp(-alfa*(s/dr)**2)
            dy=-2.d0*alfa*y*s/dr**2
            ddy=-2.d0*alfa*y*(1.d0-2.d0*alfa*(s/dr)**2)/dr**2
        end if
        fn2=y    !cm^-3
        fnp=dy
        fnpp=ddy
    end

    real(wp) function ft(x)
    !! electron temperature, erg
        use constants, only: zero
        use spline_module
        real(wp), intent(in) :: x
        real(wp) :: pa, r, y, dy
        real(wp), parameter :: alfa=4.d0, dr=.02d0
        pa=abs(x) !#@sav
        if(pa.le.rh(nspl)) then
            call splnt(rh,tem,y2tm,nspl,pa,y,dy)
        else
            r=pa-rh(nspl)
            y=tem(nspl)*exp(-alfa*(r/dr)**2)
        end if
        !!      ft=y            ! kev
        ft=y*0.16d-8      ! erg
    end    

    real(wp) function fti(x)
    !! ion temperature, kev
        use constants, only: zero
        use spline_module      
        real(wp), intent(in) :: x
        real(wp) :: pa, r, y, dy
        real(wp), parameter :: alfa=4.d0, dr=.02d0
        pa=abs(x) !#@sav
        if(pa.le.rh(nspl)) then
            call splnt(rh,temi,y2tmi,nspl,pa,y,dy)
        else
            r=pa-rh(nspl)
            y=temi(nspl)*exp(-alfa*(r/dr)**2)
        end if
        fti=y              ! kev
    end
    
    real(wp) function zefff(x)
    !! z_effective profile
        use constants, only: zero    
        use spline_module      
        real(wp), intent(in) :: x
        real(wp) :: pa, r, y, dy
        real(wp), parameter :: alfa=4.d0, dr=.02d0
        pa=abs(x) !#@sav
        if(pa.le.rh(nspl)) then
            call splnt(rh,zeff,y2zeff,nspl,pa,y,dy)
        else
            r=pa-rh(nspl)
            y=zeff(nspl)*exp(-alfa*(r/dr)**2)
        end if
        zefff=y
    end


    subroutine calc_enorm
        use constants
        use rt_parameters, only: nr, inew
        use spline_module
        use maxwell
        use lock_module
        implicit none
        integer j, klo,khi,ierr
        real(wp) :: efld
        real(wp) :: r, pn, vt, tmp, xlogj,vmax
        real(wp) :: fnr,fnrr, dens
        !real*8 fn1,fn2
        do j=1,nr
            r=dble(j)/dble(nr+1)
            call lock(rh,nspl,r,klo,khi,ierr)
            if(ierr.eq.1) then
                write(*,*)'lock error in saveprofiles, Efield'
                write(*,*)'j=',j,' rh(j)=',rh(j),' r=',r
                pause
                stop
            end if
            call linf(rh,afld,r,efld,klo,khi)
            if(inew.eq.0) then !vardens
                pn=fn1(r,fnr)
            else
                pn=fn2(r,fnr,fnrr)
            end if
            vt=fvt(r)
            tmp=ft(r)/0.16d-8  !Te,  KeV
            dens=pn/1.d+13     !10^13 cm^-3
            xlogj=dlog(5.1527d7*tmp*16.d0*dsqrt(tmp)/dsqrt(dens))
            enorm(j)=(3.835d0/xlogj)*efld*tmp/dens
            enorm(j)=enorm(j)*5.d0/(5.d0+zefff(r))
            !!fst(j)=pn*xlogj*c0**4/pi4/vt**3
            fst(j)=((5.d0+zefff(r))/5.d0)*pn*xlogj*c0**4/pi4/vt**3
        end do        
    end subroutine

    subroutine init_maxwell
        use constants
        use rt_parameters, only: nr, inew
        use spline_module
        use maxwell        
        implicit none
        integer j
        real(wp) r, vclt
        do j=1,nr
            r=dble(j)/dble(nr+1)
            vclt=3.d10/fvt(r)
            !print *, vclt
            !call init_vi(vclt, vij(:,j))
            vij(1:i0,j) = create_vt_grid(vclt)
            call init_fmaxw_classic(vclt,enorm(j),fij(:,j,1),dfij(:,j,1))
            call init_fmaxw_ext(vclt,enorm(j),fij(:,j,2),dfij(:,j,2))     
          end do
          fij0(:,:,:)=fij(:,:,:)
          dij(:,:,:)=zero

    end subroutine

    real(wp) function obeom(ptet,pa)
        use constants
        use approximation
        implicit real*8 (a-h,o-z)
        !common /a0befr/ pi,pi2
        !common /a0ef1/ cltn
        !common /a0k/ cdl(10),cly(10),cgm(10),cmy(10),ncoef
        parameter(pa0=0.d0)
        xdl=fdf(pa,cdl,ncoef,xdlp)
        xly=fdf(pa,cly,ncoef,xlyp)
        xgm=fdf(pa,cgm,ncoef,xgmp)
        xlyv=xlyp*pa+xly
        cotet=dcos(ptet)
        sitet=dsin(ptet)
        dxdr=-xdlp+cotet-xgmp*sitet**2
        dxdt=-(pa+two*xgm*cotet)*sitet
        dzdr=xlyv*sitet
        dzdt=xly*pa*cotet
        x0=r0/rm-xdl+pa*cotet-xgm*sitet**2
        dxdrdt=-sitet-two*xgmp*sitet*cotet
        dzdrdt=xlyv*cotet
        dxdtdt=-pa*cotet-two*xgm*(cotet**2-sitet**2)
        dzdtdt=-xly*pa*sitet
        x0t=dxdt
!--------------------------------------
! components of metric tensor
!--------------------------------------
        g11=dxdr**2+dzdr**2
        g22=dxdt**2+dzdt**2
        g12=dxdr*dxdt+dzdr*dzdt
        g33=x0**2
        xj=(dzdr*dxdt-dxdr*dzdt)**2  !gg=g11*g22-g12*g12
        g=xj*g33
        obeom=dsqrt(g)
    end

    real(wp) function ploshad(ptet,pa)
        use constants
        use approximation
        implicit real*8 (a-h,o-z)
        !common /a0befr/ pi,pi2
        !common /a0ef1/ cltn
        !common /a0k/ cdl(10),cly(10),cgm(10),cmy(10),ncoef
        parameter(pa0=0.d0)
        xdl=fdf(pa,cdl,ncoef,xdlp)
        xly=fdf(pa,cly,ncoef,xlyp)
        xgm=fdf(pa,cgm,ncoef,xgmp)
        xlyv=xlyp*pa+xly
        cotet=dcos(ptet)
        sitet=dsin(ptet)
        dxdr=-xdlp+cotet-xgmp*sitet**2
        dxdt=-(pa+two*xgm*cotet)*sitet
        dzdr=xlyv*sitet
        dzdt=xly*pa*cotet
        x0=r0/rm-xdl+pa*cotet-xgm*sitet**2
        dxdrdt=-sitet-two*xgmp*sitet*cotet
        dzdrdt=xlyv*cotet
        dxdtdt=-pa*cotet-two*xgm*(cotet**2-sitet**2)
        dzdtdt=-xly*pa*sitet
        x0t=dxdt
        !--------------------------------------
        ! components of metric tensor
        !--------------------------------------
        g11=dxdr**2+dzdr**2
        g22=dxdt**2+dzdt**2
        g12=dxdr*dxdt+dzdr*dzdt
        xj=(dzdr*dxdt-dxdr*dzdt)**2  !gg=g11*g22-g12*g12
        ploshad=dsqrt(xj)
    end

    real(wp) function gaussint(f,a,b,r,eps)
    !! что-то про гаусс
        implicit none
        real(wp) w(12), x(12)
        real(wp) f, a, b, r, eps
        real(wp) aa, bb, c1, c2, s8, s16, u, y, delta
        integer i
        !!      save w,x,const !sav#
        real(wp), parameter :: const = 1.0d-12
        data w &
        /0.101228536290376, 0.222381034453374, 0.313706645877887, &
         0.362683783378362, 0.027152459411754, 0.062253523938648, &
         0.095158511682493, 0.124628971255534, 0.149595988816577, &
         0.169156519395003, 0.182603415044924, 0.189450610455069/
        data x &
        /0.960289856497536, 0.796666477413627, 0.525532409916329, &
         0.183434642495650, 0.989400934991650, 0.944575023073233, &
         0.865631202387832, 0.755404408355003, 0.617876244402644, &
         0.458016777657227, 0.281603550779259, 0.095012509837637/
        delta=const*dabs(a-b)
        gaussint=0d0
        aa=a
  5     y=b-aa
        if (dabs(y).le.delta) return
  2     bb=aa+y
        c1=0.5d0*(aa+bb)
        c2=c1-aa
        s8=0d0
        s16=0d0
        do i = 1,4
            u=x(i)*c2
            s8=s8+w(i)*(f(c1+u,r)+f(c1-u,r))
        end do 
        do i = 5,12
            u=x(i)*c2
            s16=s16+w(i)*(f(c1+u,r)+f(c1-u,r))
        end do
        s8=s8*c2
        s16=s16*c2
        if(dabs(s16-s8) .gt. eps*(1d0+dabs(s16))) go to 4
        gaussint=gaussint+s16
        aa=bb
        go to 5
  4     y=0.5d0*y
        if(dabs(y) .gt. delta) go to 2
        write(*,7)
        gaussint=0d0
        return
  7     format(1x,'gaussint ... too high accuracy required')
    end

end module plasma